<template>
  <div class="channel-edit">
    <!-- <button @click="hTest">测试在子组件中修改父组件传过来的prop值</button> -->
    <!-- 当前登陆用户已经订阅的频道 -->

    <!-- 在true，false之间切换： @click="editing=!editing" -->
    <div class="channel">
      <van-cell title="我的频道" :border="false">
        <van-button size="mini" type="info" @click="editing=!editing">
          {{ editing ? '取消' : '编辑'}}
        </van-button>
      </van-cell>
      <van-grid>
        <van-grid-item
        v-for="(item, idx) in channels"
        :key="item.id"
        @click="hClickMyChannel(item, idx)"
        :class="{'cur': idx===activeIndex}"
        >
          <span>{{item.name}}</span>
          <!--
            我的频道上的x标记
            1. 只处在编辑状态时，才可见
            2. 推荐频道始终是不能删除的，它不应该显示 x
          -->
          <van-icon name="cross" class="btn" v-show="editing && idx!==0"></van-icon>
        </van-grid-item>
      </van-grid>
    </div>

    <!-- 当前登陆用户没有订阅的频道 -->
    <div class="channel">
      <van-cell title="可选频道" :border="false"></van-cell>
      <van-grid>
        <van-grid-item
        v-for="item in recommendChannels"
        :key="item.id"
        @click="hAddChannel(item)">
          <span>{{item.name}}</span>
        </van-grid-item>
      </van-grid>
    </div>
  </div>
</template>

<script>
import { getAllChannels, addChannel, deleteChannel } from '@/api/channel'
export default {
  name: 'ChannelEdit',
  // props: ['channels', 'activeIndex'], // 接收父组件传入的已经订阅的频道, 当前活动的下标
  props: {
    // propName: {
    //   type: Number, // 支持从父组件传入时，它的类型
    //   required: true, // 是否是必须要传入的
    //   default: 0, // 默认值, 如果required是true，则default无效。
    //   validator (val) { // 自定义的校验函数
    //     val 就是从父组件中传入的值
    //     如果返回true,表示prop 值合法的；如果返回false,就会在控制台给出提示
    //     console.log(val)
    //     if (val > 3) {
    //       return true
    //     } else {
    //       return false
    //     }
    //   }
    // }
    channels: {
      type: Array,
      required: true
    },
    activeIndex: {
      type: Number,
      required: true
    }
  },
  data () {
    return {
      editing: false, // 是否处于编辑状态
      allChannels: [] // 所有频道
    }
  },
  created () {
    this.loadAllChannels()
  },
  // 可选频道 = 所有频道 - 已经订阅的频道

  // 问题1： 在哪里去保存可选频道？只有存下来，可能去做v-for
  //    1）额外补充一个数据项。
  //       不好！因为这个可选频道会变化：用户删除了频道，或者是添加频道.....
  //    2) 额外补充一个computed
  //       正解！计算属性的特点是数据变化了，计算属性自动更新。
  // 问题2： 如何做数组的减法？
  computed: {
    recommendChannels () {
      console.log('recommendChannels....计算了一次')
      // this.allChannels - this.channels
      //     对于allChannels中的元素进行过滤: 只保存那些没有在 channels中出现的元素， 作为减法的结果
      const result = this.allChannels.filter(channel => {
        // 只要那些个 没有在 已经订阅的频道中 出现的频道
        const idx = this.channels.findIndex(item => item.id === channel.id)
        // 如果找到，idx肯定不是-1; 找不到，就是-1
        return idx === -1
      })
      return result
    }
  },
  methods: {
    hTest () {
      // alert(1)
      // this.activeIndex = 1000 // 不能改
      // 在子组件中确实不应该直接修改父组件传递的prop
      //     直接修改的意义是不能通过 = 来修改。
      // 但是，如果prop是一个引用数据类型(数组，对象),则可以 间接修改 prop.
      // 这就提供了一种直接在子组件修改父组件中数据的方式。
      // this.channels = [{ id: 100, name: 'test' }]
      // this.channels.push({ id: 100, name: 'test' })
    },
    async loadAllChannels () {
      const result = await getAllChannels()
      this.allChannels = result.data.data.channels
    },
    // 用户点击了 我的频道 中的某一项
    // 有两种情况：
    // 1. 如果是普通状态，则是切换频道
    //      目标： 1）关闭弹层；2）切换到当前点击的频道上去
    //      这两件事，都应该是父组件来做
    // 2. 如果是编辑状态，则是删除频道
    async hClickMyChannel (channel, idx) {
      // 编辑状态，是删除频道
      if (this.editing) {
        // 推荐频道是绝对不能删除的。
        if (channel.id === 0) {
          return
        }
        // 1. 请求接口。不再订阅这个频道了
        const result = await deleteChannel(channel.id)
        console.log(result)
        // 2. 更新视图：从已订阅的频道中删除当前项
        // 下面一句有三个效果
        this.channels.splice(idx, 1)
        // 1） 修改已订阅频道：减少一项
        // 2） 修改  可选频道：多出一项
        // 由于计算属性recommandChannel的计算过程依赖于this.channels，当this.channels变化时
        // 计算属性会重新执行，所以 可选频道会自动多出一项
        // 3) 它会修改父组件中channels。原因是channels本身就是通过props传递过来的引用类型的数据
        //    会直接导致父组件中的频道列表减少一项

        // fix bug
        // 如果当前要删除的频道 在 当前选中的频道之前，则还要去修改一下父组件中activeIndx
        if (idx < this.activeIndex) {
          this.$emit('updateCurIndex', this.activeIndex - 1)
        }
      } else {
        // 抛出事件
        this.$emit('updateCurChannel', channel)
      }
    },
    // 用户在某个推荐频道上做了一次点击
    async hAddChannel (channel) {
      // 1. 组装数据，改造成api需要的格式
      //    在用户原来的订阅频道的基础上，添加这个频道
      // let curChannelList = 在用户原来的订阅频道列表+ 添加这个频道
      let curChannelList = [...this.channels, channel]
      // 映射成参数要求的格式
      curChannelList = curChannelList.map((item, idx) => {
        return {
          id: item.id,
          seq: idx
        }
      })
      // 去掉 推荐频道. 由于推荐频道是在第一个位置，所以这里直接删除
      curChannelList.splice(0, 1)

      console.log(this.channels, curChannelList)
      // 2. 调用接口
      // 如果添加操作不报错，说明添加是成功的，所以在后续的代码更新本地的数据
      // 而不是重新发请求再拿一次数据。
      const result = await addChannel(curChannelList)
      console.log(result)
      // 3. 更新视图
      this.channels.push(channel)
      // 1） 修改已订阅频道：多出一项
      // 2） 修改  可选频道：减少一项
      // 由于计算属性recommandChannel的计算过程依赖于this.channels，当this.channels变化时
      // 计算属性会重新执行，所以 可选频道会自动减少一项
      // 3) 它会修改父组件中channels。原因是channels本身就是通过props传递过来的引用类型的数据
      //    会直接导致父组件中的频道列表多出一项
    }
  }
}
</script>

<style lang="less" scoped>
  .channel{
    padding:15px;
    font-size:14px;
  }
  .btn {
    position: absolute;
    top: 0;
    right: 0;
    font-size: 24px;
  }
  .cur {
    color: red;
    font-weight: bold;
  }
</style>
